import YYMessage from './index.vue'
import Vue from 'vue'

// 用于创建一个构造函数，基于 YYMessage 组件的扩展。
// 这样可以创建一个可复用的组件构造函数，可以在需要的时候动态地创建组件实例。
const MessageConstructor = Vue.extend(YYMessage)

const instances = []
const distance = 20
let messageId = 1

function isVNodeObject (obj) {
  return obj !== null && typeof obj === 'object' && hasOwnProperty.call(obj, 'componentOptions');
}

function processOptions (options) {
  if (typeof options === 'string') {
    return { message: options }
  } else {
    return options || {}
  }
}

function computeVerticalOffset (offset) {
  let verticalOffset = offset
  // if (instances.length > 0) {
  //   const instancesLast = instances[instances.length - 1]
  //   verticalOffset = offset + instancesLast.verticalOffset + instancesLast.$el.offsetHeight
  // }
  verticalOffset = instances.reduce((acc, cur) => {
    return acc + cur.$el.offsetHeight + distance
  }, verticalOffset)
  return verticalOffset
}

export const Message = (options) => {

  let processedOptions = processOptions(options)

  // 这个 js 中的 data 优先级比 index.vue 的优先级更高
  // 实例化以后，这里的 instance 就相当于 message 组件中的 this 对象了
  const instance = new MessageConstructor({
    data () {
      return processedOptions
    }
  })

  // 如果是 VNode 对象，那么不可以直接通过 data 中的属性来进行渲染
  // 而是需要使用插槽！！！
  if (isVNodeObject(instance.message)) {
    instance.$slots.default = [processedOptions.message]
    instance.message = null
  }

  instance.id = 'message' + messageId++

  let offset = processedOptions.offset || 20
  instance.offset = offset
  instance.verticalOffset = computeVerticalOffset(offset)

  // 处理弹窗的onClose事件
  let userOnClose = options.onClose
  instance.onClose = () => {
    console.log('打印')
    let id = instance.id
    Message.close(id, userOnClose)
  }

  instances.push(instance)

  instance.$mount()
  document.body.appendChild(instance.$el)
};

// 用于支持this.$message.success('成功信息')的使用方式
['info', 'success', 'warning', 'error'].forEach((type) => {
  Message[type] = (options) => {
    if (Object.prototype.toString.call(options) === '[object Object]' && !isVNodeObject(options)) {
      return Message({
        ...options,
        type
      })
    }
    return Message({
      message: options,
      type
    })
  }
})

Message.close = (id, userOnClose) => {
  let removeInstanceIndex = instances.findIndex(instance => instance.id === id)
  if (removeInstanceIndex === -1) { return }
  let removeInstance = instances[removeInstanceIndex]
  let removeHeight = removeInstance.$el.offsetHeight
  if (typeof userOnClose === 'function') {
    userOnClose(removeInstance)
  }
  instances.splice(removeInstanceIndex, 1)
  let instancesLen = instances.length
  for (let i = removeInstanceIndex; i < instancesLen; i++) {
    const dom = instances[i].$el
    dom.style.top = parseInt(dom.style.top) - removeHeight - distance + 'px'
  }
}

Message.closeAll = () => {
  for (let i = 0; i < instances.length; i++) {
    instances[0].close();
  }
}